package com.aqie.rabbit.controller;

import com.aqie.rabbit.access.AccessLimit;
import com.aqie.rabbit.bean.api.account.AccountRspModel;
import com.aqie.rabbit.bean.api.account.LoginModel;
import com.aqie.rabbit.bean.api.account.RegisterModel;
import com.aqie.rabbit.bean.api.base.CodeMsg;
import com.aqie.rabbit.bean.api.base.PushModel;
import com.aqie.rabbit.bean.api.base.ResponseModel;
import com.aqie.rabbit.bean.api.user.UpdateInfoModel;
import com.aqie.rabbit.bean.card.UserCard;
import com.aqie.rabbit.bean.db.User;
import com.aqie.rabbit.service.IPushService;
import com.aqie.rabbit.service.ISmsService;
import com.aqie.rabbit.service.Impl.UserServiceImpl;
import com.aqie.rabbit.utils.PushDispatcher;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.web.bind.annotation.*;

import javax.ws.rs.DefaultValue;
import java.util.List;
import java.util.stream.Collectors;


@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private ISmsService smsService;

    @Autowired
    private IPushService pushService;

    @PostMapping("/register")
    public ResponseModel<AccountRspModel> register(@RequestBody RegisterModel model){
        // 1. 参数校验
        if (!RegisterModel.check(model)) {
            // 返回参数异常
            return ResponseModel.error(CodeMsg.PARAMETER_ERROR);
        }

        User user = userService.findByPhone(model.getAccount().trim());
        if (user != null){
            return ResponseModel.error(CodeMsg.USER_MOBILE_EXIT_ERROR);
        }

        user = userService.findByName(model.getName().trim());
        if (user != null){
            return ResponseModel.error(CodeMsg.USER_NAME_EXIST_ERROR);
        }
        // 2. 注册逻辑
        user = userService.register(model);
        if (user != null){
            return bindPushId(model.getPushId(), user);
        }else{
            return ResponseModel.error(CodeMsg.ACCOUNT_REGISTER_ERROR);
        }

    }

    @PostMapping("/login")
    public ResponseModel<AccountRspModel> login(@RequestBody LoginModel model){
        if (!LoginModel.check(model)) {
            // 返回参数异常
            return ResponseModel.error(CodeMsg.PARAMETER_ERROR);
        }


        User user = userService.login(model);
        if (user != null) {
            return bindPushId(model.getPushId(), user);
        } else {
            // 登录失败
            return ResponseModel.error(CodeMsg.USER_NAME_OR_PASSWORD_ERROR);
        }
    }

    private ResponseModel<AccountRspModel> bindPushId(String pushId, User user) {
        // 如果有携带PushId
        if (!Strings.isNullOrEmpty(pushId)) {
            user = userService.bindPushId(user,pushId);
            if (user == null) {
                // 绑定失败则是服务器异常
                return ResponseModel.error(CodeMsg.BIND_PUSH_ID_ERROR);
            }
            AccountRspModel rspModel = new AccountRspModel(user, true);
            return ResponseModel.success(rspModel);
        }
        // 返回当前的账户
        AccountRspModel rspModel = new AccountRspModel(user);
        return ResponseModel.success(rspModel);
    }

    @PostMapping("/bind/{pushId}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<AccountRspModel> bind(@PathVariable(value = "pushId") String pushId){
        if (Strings.isNullOrEmpty(pushId)){
            return ResponseModel.error(CodeMsg.PARAMETER_ERROR);
        }

        User self = userService.getUser();

        if (self == null){
            return ResponseModel.error(CodeMsg.TOKEN_INVALID_ERROR);
        }
        return bindPushId(pushId,self);
    }

    @GetMapping("self")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<UserCard> getSelf(){
        User self = userService.getUser();
        UserCard card = new UserCard(self, true);
        return  ResponseModel.success(card);
    }

    @PutMapping
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<UserCard> update(@RequestBody UpdateInfoModel model) {
        if (!UpdateInfoModel.check(model)) {
            return ResponseModel.error(CodeMsg.PARAMETER_ERROR);
        }
        User self = userService.getUser();

        if (self == null){
            return ResponseModel.error(CodeMsg.USER_NOT_LOGIN_ERROR);
        }


        self = model.updateToUser(self);
        try {
            self = userService.update(self);
        }catch (DataIntegrityViolationException e) {
            return ResponseModel.error(CodeMsg.DATABASE_INTEGRITY_VIOLATION_ERROR);
        }catch (DataAccessException e){
            return ResponseModel.error(CodeMsg.DATABASE_ERROR);
        }
        if (self == null){
            return ResponseModel.error(CodeMsg.USER_UPDATE_ERROR);
        }
        // 构建自己用户信息
        UserCard card = new UserCard(self, true);
        return  ResponseModel.success(card);
    }

    @PostMapping("/sendSms")
    @AccessLimit(seconds = 86400,maxCount = 1,needLogin = false)
    public ResponseModel sendSms(String phone){
        return smsService.sendSms(phone);
    }

    /**
     * 获取指定id 用户信息
     * 可以查询自己直接返回(必须登录状态) 或者 根据id在数据库查询
     * @param id
     * @return
     */
    @GetMapping("id/{id}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<UserCard> getUser(@PathVariable("id") String id){
        if (Strings.isNullOrEmpty(id)){
            return ResponseModel.error(CodeMsg.PARAMETER_ERROR);
        }

        User self = userService.getUser();
        if (self.getId().equalsIgnoreCase(id)) {
            // 返回自己，不必查询数据库
            return ResponseModel.success(new UserCard(self, true));
        }

        User user = userService.findById(id);
        if (user == null){
            return ResponseModel.error(CodeMsg.USER_ID_EXIST_ERROR);
        }
        // 查询我是否关注查询用户
        boolean isFollow = userService.getUserFollow(self.getId(),user.getId()) != null;
        return ResponseModel.success(new UserCard(user,isFollow));
    }

    /**
     * 拉取联系人
     * todo 拉取某一时间段后联系人
     */
    @GetMapping("contact")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<UserCard>> contact(){
        User self = userService.getUser();
        List<User> users  = userService.contact(self.getId());
        if (users == null){
            return ResponseModel.error(CodeMsg.FOLLOW_USER_LIST_EMPTY_ERROR);
        }

        // testPush(self);

        List<UserCard> userCards = users.stream()
                // map操作，相当于转置操作，User->UserCard
                .map(user -> new UserCard(user, true))
                .collect(Collectors.toList());
        return ResponseModel.success(userCards);
    }

    // 测试推送消息
    private void testPush(User self) {
        PushModel model = new PushModel();
        model.add(new PushModel.Entity(0,"hello world"));
        PushDispatcher dispatcher = new PushDispatcher();
        dispatcher.add(self,model);
        dispatcher.submit();
    }


    /**
     * 关注指定ID用户(这里采用的互相关注)
     * @param followId 备注默认没有加
     * todo
     * @return 修改关注状态 返回被关注人UserCard
     */
    @PutMapping("follow/{followId}")
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<UserCard> follow(@PathVariable("followId") String followId) {
        User self = userService.getUser();

        // 1.不能关注我自己
        if (self.getId().equalsIgnoreCase(followId)
                || Strings.isNullOrEmpty(followId)) {
            // 返回参数异常
            return ResponseModel.error(CodeMsg.FOLLOW_YOURSELF_ERROR);
        }

        // 2.找到我关注的人
        User followUser = userService.findById(followId);
        if (followUser == null){
            return ResponseModel.error(CodeMsg.FOLLOW_USER_ID_NOT_EXIT_ERROR);
        }

        // 3. 查询登录用户是否已关注查询用户
        boolean isFollow = userService.getUserFollow(self.getId(),followUser.getId()) != null;
        if (isFollow){
            return ResponseModel.error(CodeMsg.ALREADY_FOLLOW_ERROR);
        }
        // 4. 修改关注状态,返回关注人信息
        followUser = userService.follow(self,followUser,null);
        // 互相关注
        userService.follow(followUser,self,null);

        // 5. 给对方推送关注信息
        pushService.pushFollow(followUser, new UserCard(self));
        return ResponseModel.success(new UserCard(followUser, true));
    }

    /**
     *
     * @param name 名字为任意字符 可为空
     * 不可以搜索自己
     * @return
     */
    @GetMapping(value = {"/search/{name:(?:.*)?}","/search"})
    @AccessLimit(seconds = 5,maxCount = 5)
    public ResponseModel<List<UserCard>> search(@DefaultValue("")@PathVariable(value = "name",required = false) String name){
        User self = userService.getUser();

        // 先查询数据
        if (Strings.isNullOrEmpty(name)) name = "";

        List<User> searchUsers = userService.search(name, self.getId());
        if (searchUsers == null || searchUsers.size() == 0){
            return ResponseModel.error(CodeMsg.SEARCH_RESULT_EMPTY_ERROR);
        }

        /**
         * 查询的人封装为UserCard
         * 判断这些人是否已关注
         * 如果有，则返回的关注状态中应设置好状态
         * 如果关注列表为空 则直接置位null
         */

        final List<User> contacts = userService.contact(self.getId());

        // User -> UserCard
        List<UserCard> userCards;
        if (contacts != null) {
            userCards = searchUsers.stream()
                    .map(user -> {
                        // 判断这个人是否是我自己，或者是我的联系人中的人
                        boolean isFollow = user.getId().equalsIgnoreCase(self.getId())
                                // 进行联系人的任意匹配，匹配其中的Id字段
                                || contacts.stream().anyMatch(
                                contactUser -> contactUser.getId()
                                        .equalsIgnoreCase(user.getId())
                        );

                        return new UserCard(user, isFollow);
                    }).collect(Collectors.toList());
        }else {
            userCards = searchUsers.stream()
                    // map操作，相当于转置操作，User->UserCard
                    .map(user -> new UserCard(user, false))
                    .collect(Collectors.toList());
        }
        return ResponseModel.success(userCards);
    }
}
